package redis

import (
	"fmt"
	"gitee.com/manoshi/go-util/conf"
	"gitee.com/manoshi/go-util/const/YorN"
	"gitee.com/manoshi/go-util/log"
	"github.com/go-redis/redis"
	"time"
)

func TestLog() {
	log.Info("Redis 测试")
}

var redisClient *redis.Client

func Init() {
	redisClient = redis.NewClient(&redis.Options{
		Addr:         fmt.Sprintf("%s:%d", conf.Redis.RedisHost, conf.Redis.RedisPort),
		Password:     conf.Redis.RedisPwd,
		DB:           conf.Redis.RedisDb,                                   // redis一共16个库，指定其中一个库即可
		PoolSize:     conf.Redis.PoolSize,                                  //最大连接数 默认cpu数*10
		MinIdleConns: conf.Redis.MinIdleConns,                              //最小空闲连接数
		ReadTimeout:  time.Duration(conf.Redis.ReadTimeout) * time.Second,  //取超时间 单位秒 默认值为3秒
		WriteTimeout: time.Duration(conf.Redis.WriteTimeout) * time.Second, // 写入超时时间 单位秒 默认与读超时时间一致
	})
	_, err := redisClient.Ping().Result()
	if err != nil {
		log.Error(fmt.Sprintf("Redis connect error ：%s", err.Error()))
	} else {
		log.Info("Redis connect success")
	}
	return
}

func getDb() *redis.Client {
	return redisClient
}

func Incr(key string) int64 {
	r := getDb().Incr(key)
	return r.Val()
}

func IncrBy(key string, n int64) int64 {
	r := getDb().IncrBy(key, n)
	return r.Val()
}

func DecrBy(key string, n int64) int64 {
	r := getDb().DecrBy(key, n)
	return r.Val()
}

func Exists(key string) bool {
	r := getDb().Exists(key)
	return r.Val() > 0
}

//SwitchOpen 在redis中存0或1,1代表OK
func SwitchOpen(key string) bool {
	r := GetString(key)
	log.Debug(fmt.Sprintf("缓存[%s]数据为：%s", key, r))
	return r == YorN.Y
}

func GetString(key string) string {
	r := getDb().Get(key)
	return r.Val()
}

func Get(key string) []byte {
	r := getDb().Get(key)
	rByte, err := r.Bytes()
	if err != nil {
		log.Warn(fmt.Sprintf("获取缓存错误：%s", err.Error()))
	}
	return rByte
}

func Set(k, v string) error {
	e := getDb().Set(k, v, 0).Err()
	if e == nil {
		log.Debug(fmt.Sprintf("设置缓存成功：%s %s", k, v))
	} else {
		log.Debug(fmt.Sprintf("设置缓存失败：%s %s %s", k, v, e))
	}
	return e
}

func SetNx(k, v string, timeoutSecond int) error {
	e := getDb().Set(k, v, time.Duration(timeoutSecond)*time.Second).Err()
	if e == nil {
		log.Debug(fmt.Sprintf("设置缓存成功：%s %s", k, v))
	} else {
		log.Debug(fmt.Sprintf("设置缓存失败：%s %s %s", k, v, e))
	}
	return e
}

func Del(ks ...string) (int64, error) {
	return getDb().Del(ks...).Result()
}

func Expire(k string, t int) bool {
	b := getDb().Expire(k, time.Duration(t)*time.Second)
	if b.Val() {
		log.Debug(fmt.Sprintf("设置缓存过期成功：%s %d", k, t))
	} else {
		log.Warn(fmt.Sprintf("设置缓存过期失败：%s %d", k, t))
	}
	return b.Val()

}

var lockScript string = `if redis.call("exists",KEYS[1]) == 0 then
    local lockSrc = redis.call("setex",KEYS[1],unpack(ARGV))
    if lockSrc then
        return "1"
    end
        return "0"
end`

var unlockScript string = `if redis.call('get', KEYS[1]) == ARGV[1] then 
	local lockSrc = redis.call('del', KEYS[1])
	if lockSrc then
		return "1"
	end 
		return "0"
end`

// Lock 抢锁。抢到锁返回true，否则false。只抢一次
// 所有参数必传，超时时间单位秒
func Lock(k, uniqueValue string, timeoutSecond int) bool {
	r, _ := getDb().Eval(lockScript, []string{k}, timeoutSecond, uniqueValue).String()
	if r == "1" {
		return true
	}
	return false
}

// Unlock 解锁
// 所有参数必传
func Unlock(k, uniqueValue string) bool {
	r, _ := getDb().Eval(unlockScript, []string{k}, uniqueValue).String()
	if r == "1" {
		return true
	}
	return false
}

// LockWait 抢锁,在规定的时间内直到抢锁成功或者超时失败。抢到锁返回true，否则false
// k	必须
// uniqueValue	必须
// timeoutSecond	锁自动释放时间，必须
// lockTimeoutSecond	抢锁超时时间，默认1分钟
func LockWait(k, uniqueValue string, timeoutSecond int, lockTimeoutSecond int) bool {
	if lockTimeoutSecond == 0 {
		lockTimeoutSecond = 60
	}
	loopCount := lockTimeoutSecond * 10
	for i := 0; i < loopCount; i++ {
		if Lock(k, uniqueValue, timeoutSecond) {
			return true
		}
		time.Sleep(time.Duration(100) * time.Millisecond) //100ms
	}
	return false
}

// Hset 向一张hash表中放入数据,如果不存在将创建
func Hset(k, i, v string, timeoutSecond int) error {
	e := getDb().HSet(k, i, v).Err()
	if e == nil {
		log.Debug(fmt.Sprintf("设置缓存成功：%s %s %s", k, i, v))
		if timeoutSecond > 0 {
			Expire(k, timeoutSecond)
		}
	} else {
		log.Debug(fmt.Sprintf("设置缓存失败：%s %s %s %s", k, i, v, e))
	}
	return e
}

// HGet 从hash中获取值
func HGet(k, i string) (string, error) {
	r, e := getDb().HGet(k, i).Result()
	return r, e
}

// HGetAll 从hash中获key所有的取值
func HGetAll(k string) (map[string]string, error) {
	return getDb().HGetAll(k).Result()
}

// Hdel 从hash中删除
func Hdel(k string, is ...string) (int64, error) {
	r, e := getDb().HDel(k, is...).Result()
	return r, e
}

// HMSet 向一张hash表中放入数据,如果不存在将创建
func HMSet(k string, fields map[string]interface{}, timeoutSecond int) error {
	e := getDb().HMSet(k, fields).Err()
	if e == nil {
		log.Debug(fmt.Sprintf("设置缓存成功：%s %s", k, fields))
		if timeoutSecond > 0 {
			Expire(k, timeoutSecond)
		}
	} else {
		log.Debug(fmt.Sprintf("设置缓存失败：%s %s %s", k, fields, e))
	}
	return e
}

func HMget(k string, is ...string) ([]interface{}, error) {
	return getDb().HMGet(k, is...).Result()
}

func ZAdd(k, v string, score float64) (interface{}, error) {
	return getDb().ZAdd(k, redis.Z{
		Score:  score,
		Member: v,
	}).Result()
}

func ZCard(k string) (interface{}, error) {
	return getDb().ZCard(k).Result()
}

func ZRank(k, v string) (interface{}, error) {
	return getDb().ZRank(k, v).Result()
}

func ZRemRangeByScore(k string, min, max string) (interface{}, error) {
	return getDb().ZRemRangeByScore(k, min, max).Result()
}

func ZRem(k, v string) (interface{}, error) {
	return getDb().ZRem(k, v).Result()
}
